package com.godenwater.recv.server.szy206;

import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.filterchain.IoFilterAdapter;
import org.apache.mina.core.service.IoHandler;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 

import com.godenwater.recv.RecvConstant;
import com.godenwater.recv.server.sl651.HydroServer;

import cn.gov.mwr.szy206.IMessage;
import cn.gov.mwr.szy206.IMessageBody;
import cn.gov.mwr.szy206.SzyBuilder;
import cn.gov.mwr.szy206.SzyConst;
import cn.gov.mwr.szy206.SzyMessage;
import cn.gov.mwr.szy206.SzyMessageBody;
import cn.gov.mwr.szy206.SzyParser;
import cn.gov.mwr.szy206.body.Body02H;
import cn.gov.mwr.szy206.body.BodyDown;
import cn.gov.mwr.szy206.utils.ByteUtil;

public class ServerDataHandler extends IoFilterAdapter implements IoHandler {

	private Logger logger = LoggerFactory.getLogger(this.getClass());

	private final SzyServer server;

	private String channel;

	/**
	 * 针对多条消息接收完以后的合并处理，如图片消息，大数据消息
	 */
	private ConcurrentHashMap M3 = new ConcurrentHashMap();

	public ServerDataHandler(SzyServer server, String channel) {
		this.server = server;
		this.channel = channel;
	}

	/**
	 * 消息接收后的处理，只处理业务逻辑，此消息处理是在解码后，所以只需要关注消息体的内容
	 */
	public void messageReceived(IoSession session, Object message)
			throws Exception {

		logger
				.info("----------------------------------------------------------------------");
		logger.info("Szy接收通道" + this.channel + " 服务端已收到 "
				+ server.messageSize() + " 消息数;");

		if (message instanceof IoBuffer) {
			System.out.println(">>> SzyServerHandler message is IoBuffer ");
		}

		// 纯粹只处理报文，此消息体已经被解码为单体报文
		SzyMessage msg = (SzyMessage) message;
		SzyMessageBody body = (SzyMessageBody) msg.getBody();

		byte[] bytes = body.getContent();
		// 1.1：解析控制域C
		System.out.println("====================解析报文数据=======================");
		System.out.println(">> 报文内容：" + ByteUtil.toHexString(bytes));
		System.out.println(">> 报文长度： " + bytes.length);

		int pos = 0;
		byte control = bytes[0];
		int[] C = SzyParser.parseControl(control);
		System.out.println(">> 控制域：" + (C[0] == 1 ? "上行" : "下行") + " \t"
				+ (C[1] == 0 ? "单帧" : "多帧") + " \t" + " 传输" + C[2] + " "
				+ SzyConst.FUNC[C[3]]);
		pos = pos + 1;

		int serial = 1;
		if (C[1] == 1) {
			byte serialByte = bytes[1];
			serial = ByteUtil.bytesToUbyte(new byte[] { serialByte });
			pos = pos + 1;
		}

		// 1.2：解析地址域A
		byte[] address = new byte[5];
		System.arraycopy(bytes, pos, address, 0, address.length);
		String stcd = SzyParser.parseAddress(address);
		pos = pos + 5;

		// 1.3：解析AFN
		byte[] AFN = new byte[1];
		System.arraycopy(bytes, pos, AFN, 0, AFN.length);

		// 将测站与session关联起来
		SzyServer.getInstance().getSessionManager().bindSession( session,RecvConstant.SZY206,stcd);

		// 1、 校验消息
		boolean crcFlag = checkCRC(msg);// 校验消息体，CRC校验

		SzyMessage replyMsg = null;// 3、应答回复或重发报文请求

		if (crcFlag) {
			// 2、 存放于消息队列中，等待处理。将队列放在此处，减少了对链接报的处理
//			ChannelMessage cm = new ChannelMessage();
//			cm.setChannel(channel);
//			cm.setMessage(msg);
//			cm.setCrcFlag(crcFlag);
//			server.queuePush(cm);

			String log = "校验结果，报文CRC验证<相一致>，M2模式发送\"应答\"回复....";
			logger.info(log);

			switch (AFN[0]) {
			case (byte) 0x02:
				byte[] mode = new byte[1];
				System.arraycopy(bytes, 6, mode, 0, mode.length);

				replyMsg = replyMessage(address, C[2], mode);
				break;
			default:

			}

		} else {
			// 重发请求
			String log = "校验结果，报文CRC验证\"不一致 \"，M2模式发送\"重发\"请求....";
			logger.info(log);
			replyMsg = repeatMessage(address, C[2], C[3]);
		}

		// M3模式,最后一条报文才进行应答，然后后再考虑重发

		if (replyMsg != null) {
			logger.info("[回复报文] " + SzyBuilder.toHexString(replyMsg));
			session.write(replyMsg);
		}

		// 启动重发机制

	}

	/**
	 * 构造确认报文
	 * 
	 * @param msg
	 * @return
	 */
	public SzyMessage replyMessage(byte[] address, int FCB, byte[] mode) {

		byte control = SzyBuilder.newControl(0, 0, FCB, 0);
		Body02H body = new Body02H();
		body.setData(mode);

		SzyMessageBody msgBody = new SzyMessageBody();
		msgBody.setControl(control);
		msgBody.setAddress(address);
		msgBody.setUserData(body);

		return SzyBuilder.newMessage(msgBody);
	}

	/**
	 * 构造重发报文
	 * 
	 * @param msg
	 * @return
	 */
	public SzyMessage repeatMessage(byte[] address, int FCB, int FUNC) {

		byte control = SzyBuilder.newControl(0, 0, FCB, FUNC);

		BodyDown body = new BodyDown();
		// body.setAFN(afn);
		// body.setData(data);

		SzyMessageBody msgBody = new SzyMessageBody();
		msgBody.setControl(control);
		msgBody.setAddress(address);
		msgBody.setUserData(body);

		return SzyBuilder.newMessage(msgBody);
	}

	/**
	 * CRC校验
	 * 
	 * @param message
	 * @return
	 */
	public boolean checkCRC(SzyMessage message) {

		IMessageBody body = message.getBody();

		logger.info("校验SZY报文， 开始校验CRC...  ");

		byte[] bytes = body.getContent();
		byte[] crc = message.getCRC();
		if ((byte) crc[0] == (byte) SzyParser.parseCrc(bytes)) {
			return true;
		} else {

			return false;
		}

	}

	public void viewInfo(IMessage message) {

		System.out.println("******* 中心站查询遥测站实时数据 *******");
		System.out.println("原始包长度：25字节");
		System.out
				.println("原始包信息：7E7E0012345678FFFFFF378008020000130311173540057E13");
		System.out.println("中心站地址：255");
		System.out.println("水文特征码：00，水文测站编码：12345678");
		System.out.println("密码：FFFF");
		System.out.println("功能码：37");
		System.out.println("流水号：0，发报时间：2013-03-11 17:35:40");

	}

	/**
	 * 发送应答式消息
	 */
	public void sendAck(IoSession session) {
		// session.write(message);
	}

	/**
	 * {@inheritDoc}
	 */
	public void sessionClosed(IoSession session) throws Exception {
		logger.info("关闭会话  " + session.getRemoteAddress());
		SzyServer.getInstance().getSessionManager().removeSession(session);
	}

	/**
	 * 当session创建连接后，需添加到一个客户端中
	 */
	public void sessionCreated(IoSession session) throws Exception {
		logger.info("创建会话  " + session.getRemoteAddress());
		String log = "创建会话  " + session.getRemoteAddress();
		SzyServer.getInstance().getSessionManager().createSession(session);
	}

	/**
	 * {@inheritDoc}
	 */
	public void sessionIdle(IoSession session, IdleStatus status)
			throws Exception {
		logger.info("空闲会话  " + session.getRemoteAddress());
		SzyServer.getInstance().getSessionManager().idleSession(session);
	}

	/**
	 * {@inheritDoc}
	 */
	public void sessionOpened(IoSession session) throws Exception {
		logger.info("Session Opened...");

	}

	public void exceptionCaught(IoSession session, Throwable cause)
			throws Exception {
		session.close(true);

		// logger.info("会话出现异常  " + session.getRemoteAddress() + " \t"
		// + cause.getMessage());
		// cause.printStackTrace();
		// IoSessionLogger sessionLogger = IoSessionLogger.getLogger(session,
		// logger);
		logger.info("会话出现异常  " + session.getRemoteAddress() + " \t"
				+ cause.getMessage(), cause);

	}

	/**
	 * 消息应答事件
	 */
	public void messageSent(IoSession session, Object message) throws Exception {
		// TODO Auto-generated method stub
		logger.info("应答会话  " + session.getRemoteAddress());
		// session.close(true);
	}

	@Override
	public void inputClosed(IoSession session) throws Exception {
		// TODO Auto-generated method stub

	}
}
